// os 模块获取cpu的核数
const os = require("os");
// nodejs模块用于处理路径问题
const path = require("path");
// 引入ESLintPlugin插件: 代码检查
const ESLintPlugin = require("eslint-webpack-plugin");
// 引入HtmlWebpackPlugin插件: 自动引入js css等文件
const HtmlWebpackPlugin = require("html-webpack-plugin");
// 引入MiniCssExtractPlugin插件: 提取css成单独的文件
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// 引入CssMinimizerPlugin插件: css压缩
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
// 引入压缩js的插件
const TerserWebpackPlugin = require("terser-webpack-plugin");
// 引入压缩图片的插件
// const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
// 引入preload-webpack-plugin插件: 预加载
const PreloadWebpackPlugin = require("@vue/preload-webpack-plugin");
// 引入workbox-webpack-plugin插件: PWA
const WorkboxPlugin = require("workbox-webpack-plugin");
// 获取 cpu 核数
const threads = os.cpus().length;

// 用来获取处理样式的 loader
function getStyleLoader(pre) {
  return [
    // 执行顺序，从右到左(从下到上)
    MiniCssExtractPlugin.loader, // 提取css成单独的文件
    "css-loader", // 将CSS样式编译成commonjs的模块到js中
    // css兼容处理
    {
      loader: "postcss-loader",
      options: {
        postcssOptions: {
          plugins: [
            "postcss-preset-env", // 能解决大多数样式兼容性问题
          ],
        },
      },
    },
    pre,
  ].filter(Boolean); // 过滤掉未传参的pre
}

module.exports = {
  // 入口   webpack打包的入口文件
  entry: "./src/main.js", // 相对路径
  // 输出
  output: {
    // 所有文件的输出路径
    // __dirname 当前文件的文件夹路径
    path: path.resolve(__dirname, "../dist"), // 绝对路径
    // 入口文件的输出名称
    // [contenthash:8]使用contenthash，取8位长度
    filename: "static/js/[name].[contenthash:8].js",
    // 给打包输出的其它文件
    chunkFilename: "static/js/[name].[contenthash:8].chunk.js",
    // 图片字体等，通过type：asset处理的资源
    assetModuleFilename: "static/media/[hash:10][ext][query]",
    // 自动清空上次打包资源  原理：在打包前将path整个目录进行清空
    clean: true,
  },
  // loader 加载器
  module: {
    // loader 配置
    rules: [
      {
        oneOf: [
          // CSS
          {
            test: /\.css$/, // 检测以.css结尾的文件
            use: getStyleLoader(),
          },
          // Less
          {
            test: /\.less$/,
            use: getStyleLoader("less-loader"),
          },
          // Sass/Scss
          {
            test: /\.s[ac]ss$/,
            use: getStyleLoader("sass-loader"),
          },
          // Stylus
          {
            test: /\.styl$/,
            use: getStyleLoader("stylus-loader"),
          },
          // 图片
          {
            test: /\.(png|jpe?g|gif|webp)$/,
            type: "asset",
            parser: {
              dataUrlCondition: {
                maxSize: 10 * 1024, // 小于10kb的图片会被base64处理
              },
            },
            /* generator: {
              // 将图片文件输出到 static/imgs 目录中
              // 将图片文件命名 [hash:8][ext][query]
              // [hash:8]: hash值取8位
              // [ext]: 使用之前的文件扩展名
              // [query]: 添加之前的query参数
              filename: "static/imgs/[hash:8][ext][query]",
            }, */
          },
          // 字体文件和其它资源
          {
            test: /\.(ttf|woff|woff2|eot|svg|mp3|mp4|avi|ogg)$/,
            type: "asset/resource",
            /* generator: {
              // 输出名称
              filename: "static/media/[hash:10][ext][query]",
            }, */
          },
          // babel
          {
            test: /\.js$/,
            exclude: /node_modules/,
            // 排除node_modules文件夹下的文件
            use: [
              {
                loader: "thread-loader", // 开启多线程编译
                options: {
                  works: threads, // 进程数量
                },
              },
              {
                loader: "babel-loader",
                options: {
                  // 可以设置在全局的 babel.config.js 文件中
                  // presets: ['@babel/preset-env'],
                  cacheDirectory: true, // 开启babel缓存
                  cacheCompression: false, // 关闭缓存文件压缩
                  plugins: ["@babel/plugin-transform-runtime"], // 减少代码体积
                },
              },
            ],
          },
        ],
      },
    ],
  },
  // plugins 插件
  plugins: [
    // ESLintPlugin 配置
    new ESLintPlugin({
      // 检测哪些文件
      context: path.resolve(__dirname, "../src"),
      exclude: "node_modules",
      // 开启缓存
      cache: true,
      // 缓存文件路径
      cacheLocation: path.resolve(
        __dirname,
        "../node_modules/.cache/eslintcache"
      ),
      threads, // 开启多线程编译
    }),
    // HtmlWebpackPlugin 配置
    // 会在dist目录下生成一个index.html文件
    new HtmlWebpackPlugin({
      // template: 以 public/index.html 为模板创建文件
      // 新的html文件有两个特点：1. 结构和源文件一致 2. 自动引入打包生成的js等资源
      template: path.resolve(__dirname, "../public/index.html"),
    }),
    // MiniCssExtractPlugin 配置
    // 提取css成单独文件
    new MiniCssExtractPlugin({
      // 定义输出文件名和目录
      filename: "static/css/[name].[contenthash:8].css",
      chunkFilename: "static/css[name].[contenthash:8].chunk.css",
    }),
    // CssMinimizerPlugin配置
    /* new CssMinimizerPlugin(),
    new TerserWebpackPlugin({
      parallel: threads, // 开启多线程压缩
    }) */
    new PreloadWebpackPlugin({
      rel: "preload",
      as: "script",
      // rel:"prefetch"
    }),
    // PWA 配置
    new WorkboxPlugin.GenerateSW({
      // 这些选项帮助快速启用 ServiceWorkers
      // 不允许遗留任何“旧的” ServiceWorkers
      clientsClaim: true,
      skipWaiting: true,
    }),
  ],
  optimization: {
    // 压缩操作
    minimizer: [
      new CssMinimizerPlugin(), // 压缩css
      new TerserWebpackPlugin({
        // 压缩js
        parallel: threads, // 开启多线程压缩
      }),
      // 压缩图片
      /* new ImageMinimizerPlugin({
        minimizer: {
          implementation: ImageMinimizerPlugin.imageminGenerate,
          options: {
            plugins: [
              ["gifsicle", { interlaced: true }],
              ["jpegtran", { progressive: true }],
              ["optipng", { optimizationLevel: 5 }],
              [
                "svgo",
                {
                  plugins: [
                    "preset-default",
                    "prefixIds",
                    {
                      name: "sortAttrs",
                      params: {
                        xmlnsOrder: "alphabetical",
                      },
                    },
                  ],
                },
              ],
            ],
          },
        },
      }), */
    ],
    // 代码分割配置
    splitChunks: {
      chunks: "all", // 对所有模块都进行分割
      // 其它都用默认值
    },
    runtimeChunk: {
      name: (entrypoint) => `runtime-${entrypoint.name}.js`,
    },
  },
  // mode 模式
  mode: "production",
  devtool: "source-map",
};
